import sys
import marshal

if sys.version_info != (2, 3, 0, "final", 0):
    print "Freeze must be run using Python 2.3.0 as marshalling format is not guaranteed to be compatible between versions"
    sys.exit(1)

def freeze(filename):
    """Freeze the given file as a module and return a string of bytecode"""

    print "Freezing", filename

    infp = file(filename)
    source_string = infp.read() + "\n"
    infp.close()

    code_object = compile(source_string, "<frozen %s>" % filename, "exec")
    code_string = marshal.dumps(code_object)

    return code_string

def bytecode_in_C(module_name, code_string):
    s = "unsigned char %s_bytecode[] = {" % module_name;
    for i in range(0, len(code_string), 16):
        s += "\n\t"
        for c in code_string[i:i+16]:
            s += "%d," % ord(c)
    s += "\n};\n"
    return s

outfp = file("kernel_bytecode.c", "w")

outfp.write("""
/* generated by util/freeze.py */

#include "Python.h"

""")

filename = sys.argv[1]

code_string = freeze(filename)

outfp.write(bytecode_in_C("__main__", code_string))

modules = [("__main__", "__main___bytecode", len(code_string))]

for filename in sys.argv[2:]:
    code_string = freeze(filename)
    module_name = filename[:-3]
    outfp.write(bytecode_in_C(module_name, code_string))
    modules.append((module_name, "%s_bytecode" % module_name, len(code_string)))

modules.append((0, 0, 0))
                
outfp.write("struct _frozen frozenModules[] = {")

for module in modules:
    outfp.write("""\n\t{"%s", %s, %d},""" % module)

outfp.write(" /* sentinel */\n};\n")

outfp.close()

